package dbx

import (
	"gitee.com/zhongguo168a/gocodes/datax"
	"gitee.com/zhongguo168a/gocodes/datax/cachex"
	"gitee.com/zhongguo168a/gocodes/datax/mapx"
	"gitee.com/zhongguo168a/gocodes/myx/errorx"
)

// Update 只能通过编号访问
func (delayQueue *DelayQueue) Update(model IDBModelDelay, update map[string]interface{}, configs ...*Config) {
	if delayQueue.isExpired {
		panic("delay is expired")
	}

	if len(update) == 0 {
		return
	}
	delayItem := delayQueue.getOrNewItem(model)
	if delayItem.Opt == Opt_删除 {
		panic(errorx.New("object deleted", datax.M{"id": model.DBIdent()}))
	}
	switch delayItem.Opt {
	case Opt_删除:
		panic(errorx.New("文档已经被删除", datax.M{"id": model.DBIdent()}))
	case Opt_修改:
	case Opt_创建:
	default:
		delayItem.Opt = Opt_修改
	}

	conf := getConfig(configs)
	if conf == nil || !conf.EnableNil {
		update = mapx.FilterMapNotNil(update)
	}
	if delayItem.Data == nil {
		delayItem.Data = update
	} else {
		mapx.Copy(update, delayItem.Data)
	}

	delayQueue.updateOriginItem(model.DBIdent(), model, update)
	// 先修改数据模型，如果提交失败，使用Origin还原
	model.RefUpdate(update)
}

// 保存旧的数据，旧数据相同的字段不会被覆盖
func (delayQueue *DelayQueue) updateOriginItem(ident string, object cachex.IObject, update map[string]interface{}, configs ...*Config) {
	originDocument := object.ToMapByField(update)
	originItem := delayQueue.origins[ident]
	if originItem == nil {
		originItem = &OriginItem{
			object:   object,
			document: originDocument,
		}
		delayQueue.origins[ident] = originItem
	} else {
		mapx.CopyNoCover(originDocument, originItem.document)
	}
}

func (delayQueue *DelayQueue) UpdateByPath(model IDBModelDelay, update map[string]interface{}, path string, configs ...*Config) {
	if string(path[0]) != "/" {
		panic("路径的首字符必须为/")
	}
	conf := getConfig(configs)
	if conf == nil || !conf.EnableNil {
		update = mapx.FilterMapNotNil(update)
	}

	更新数据 := datax.M{}
	mapx.SetByPath(更新数据, path, update)
	delayQueue.Update(model, 更新数据)
}

// 删除数据模型内部的集合的键
func (delayQueue *DelayQueue) DictUpdate(dictItem IDBDictItem, data map[string]interface{}, configs ...*Config) {
	if delayQueue.isExpired {
		panic("delay is expired")
	}

	if len(data) == 0 {
		return
	}
	path := dictItem.DBPath()
	if string(path[0]) != "/" {
		panic("路径的首字符必须为/")
	}
	key := dictItem.DBIdent()
	model := dictItem.DBModel()
	delayItem := delayQueue.getOrNewItem(model)
	switch delayItem.Opt {
	case Opt_删除:
		panic("文档已经被删除")
	case Opt_修改:
	case Opt_创建:
	default:
		delayItem.Opt = Opt_修改
	}
	conf := getConfig(configs)
	if conf == nil || !conf.EnableNil {
		data = mapx.FilterMapNotNil(data)
	}

	delayItem.addOptItem(&OptItem{
		Opt:   DictOpt_修改,
		Path:  path + "/" + key,
		Field: key,
		Data:  data,
	})

	delayQueue.updateOriginItem(path+"/"+key, dictItem.DBObject(), data)
	// 先修改数据模型，如果提交失败，使用Origin还原
	dictItem.DBObject().RefUpdate(data)
}

// 删除数据模型内部的集合的键
func (delayQueue *DelayQueue) DictUpdateByModelPath(model IDBModelDelay, dictPath string, data interface{}, configs ...*Config) {
	delayQueue.dictUpdateByPath(model, model.RefGetObject(dictPath), dictPath, data, configs...)
}

// 删除数据模型内部的集合的键
func (delayQueue *DelayQueue) DictUpdateByDictPath(origin IDBDictItem, dictPath string, data interface{}, configs ...*Config) {
	delayQueue.dictUpdateByPath(origin.DBModel(), origin.DBModel(), origin.DBPath()+"/"+origin.DBIdent()+dictPath, data, configs...)
}

func (delayQueue *DelayQueue) dictUpdateByPath(model IDBModelDelay, dictObject cachex.IObject, dictPath string, data interface{}, configs ...*Config) {
	if delayQueue.isExpired {
		panic("delay is expired")
	}
	if dictPath == "" {
		panic("dictPath is null")
	}
	if string(dictPath[0]) != "/" {
		panic("路径的首字符必须为/")
	}
	lastPath := dictPath
	if string(lastPath[0]) != "/" {
		panic("路径的首字符必须为/")
	}
	delayItem := delayQueue.getOrNewItem(model)
	switch delayItem.Opt {
	case Opt_删除:
		panic("文档已经被删除")
	case Opt_修改:
	case Opt_创建:
	default:
		delayItem.Opt = Opt_修改
	}

	conf := getConfig(configs)
	if conf == nil || !conf.EnableNil {
		switch d := data.(type) {
		case map[string]interface{}:
			if d == nil {
				panic("不能为nil")
			}
			data = mapx.FilterMapNotNil(d)
		case nil:
			panic("不能为nil")
		}
	}

	delayItem.addOptItem(&OptItem{
		Opt:  DictOpt_修改,
		Path: dictPath,
		Data: data,
	})

	updateMap := datax.M{}
	mapx.SetByPath(updateMap, dictPath, nil)
	delayQueue.updateOriginItem(dictPath, dictObject, updateMap)
	// 先修改数据模型，如果提交失败，使用Origin还原
	dictObject.RefUpdate(updateMap)
}
